/**
 * @version 0.4.18
 * @see http://qiao.github.io/PathFinding.js/visual/
 * @see https://github.com/qiao/PathFinding.js
 */
import * as pathfinding_browser from './module/pathfinding-browser'

interface node {
    x: number,
    y: number,
    walkable: boolean,
    g?: number,
    f?: number
}


interface grid {
    width: number,
    height: number,
    nodes: node[]
}

interface Heap {
    (nodeA: node, nodeB: node): number
}

interface Node {
    new(x: number, y: number, walkable?: boolean): node
}

interface Grid {
    new(width_or_matrix: number | Array<Array<(number | boolean)>>, height: number, matrix: Array<Array<(number | boolean)>>): grid
}

interface Util {
    backtrace(node: node): Array<Array<number>>
    biBacktrace(nodeA: node, nodeB: node): Array<Array<number>>
    pathLength(path: Array<Array<number>>): number
    interpolate(x0: number, y0: number, x1: number, y1: number): Array<Array<number>>
    expandPath(path: Array<Array<number>>): Array<Array<number>>
    smoothenPath(grid: grid, path: Array<Array<number>>): Array<Array<number>>
    compressPath(path: Array<Array<number>>): Array<Array<number>>
}

enum DiagonalMovement {
    Always = 1,
    Never = 2,
    IfAtMostOneObstacle = 3,
    OnlyWhenNoObstacles = 4
}

interface Heuristic {
    manhattan(x: number, y: number): number
    euclidean(x: number, y: number): number
    octile(x: number, y: number): number
    chebyshev(x: number, y: number): number
}

interface AStarFinderOpt {
    allowDiagonal?: boolean,
    dontCrossCorners?: boolean,
    diagonalMovement?: DiagonalMovement,
    heuristic?: (x: number, y: number) => number,
    weight?: number,
}

interface BreadthFirstFinderOpt {
    allowDiagonal?: boolean,
    dontCrossCorners?: boolean,
    diagonalMovement?: DiagonalMovement,
}

type BestFirstFinderOpt = AStarFinderOpt;
type DijkstraFinder = AStarFinderOpt;

interface JumpPointFinderOpt {
    heuristic?: (x: number, y: number) => number,
    diagonalMovement?: DiagonalMovement,

    trackJumpRecursion?: boolean;
}

interface IDAStarFinderOpt {
    allowDiagonal?: boolean,
    dontCrossCorners?: boolean,
    diagonalMovement?: DiagonalMovement,
    heuristic?: (x: number, y: number) => number,
    weight?: number,
    trackRecursion?: number;
    timeLimit?: boolean;
}

interface Finder {
    AStar$(opt: AStarFinderOpt): void
    BreadthFirst$(opt: BreadthFirstFinderOpt): void
    BestFirst(opt: BestFirstFinderOpt): void
    Dijkstra$(opt: DijkstraFinder): void
    BiAStar(opt: AStarFinderOpt): void
    BiBestFirst(opt: BestFirstFinderOpt): void
    BiDijkstra$(opt: DijkstraFinder): void
    BiBreadthFirst$(opt: BreadthFirstFinderOpt): void
    JumpPoint$(opt: JumpPointFinderOpt): void
    IDAStar$(opt: IDAStarFinderOpt): void
}

export default class pathfinding {
    /**
     * 这九个函数中尾部加了$的是保证能找到最短路的
     * 从第五个开始四个前缀bi的则是双向搜索的意思
     */
    static Finder: Finder = {
        'AStar$': pathfinding_browser.AStarFinder,
        'BestFirst': pathfinding_browser.BestFirstFinder,
        'BreadthFirst$': pathfinding_browser.BreadthFirstFinder,
        'Dijkstra$': pathfinding_browser.DijkstraFinder,
        'BiAStar': pathfinding_browser.BiAStarFinder,
        'BiBestFirst': pathfinding_browser.BiBestFirstFinder,
        'BiBreadthFirst$': pathfinding_browser.BiBreadthFirstFinder,
        'BiDijkstra$': pathfinding_browser.BiDijkstraFinder,
        'IDAStar$': pathfinding_browser.IDAStarFinder,
        'JumpPoint$': pathfinding_browser.JumpPointFinder,
    }

    static Heap: Heap = pathfinding_browser.Heap
    static Node: Node = pathfinding_browser.Node
    static Grid: Grid = pathfinding_browser.Grid
    static Util: Util = pathfinding_browser.Util
    static DiagonalMovement: typeof DiagonalMovement = pathfinding_browser.DiagonalMovement
    static Heuristic: Heuristic = pathfinding_browser.Heuristic

}